﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.IO;
using System.Net.Sockets;

namespace EmbeddedSensorCloud.HTTP
{
    public sealed class Response
    {
        public Version Version { get; set; }
        public HttpStatusCode Status { get; set; }
        public Dictionary<string, string> Headers { get; set; }
        public byte[] Body { get; set; }

        public Response(string body, HttpStatusCode status = HttpStatusCode.OK) : this(status)
        {
            if (!string.IsNullOrWhiteSpace(body))
            {
                this.Body = Encoding.Default.GetBytes(body);
            }
        }

        public Response(HttpStatusCode status = HttpStatusCode.OK)
        {
            this.Headers = new Dictionary<string, string>();
            this.Version = HttpVersion.Version11;
            this.Status = status;

            this.Headers["Content-Type"] = "text/html";
            this.Headers["Connection"] = "close";
        }

        public byte[] ToResponseOutput()
        {
            StringBuilder s = new StringBuilder();

            s.AppendFormat("HTTP/{0}.{1} {2} {3}{4}", 
                this.Version.Major, 
                this.Version.Minor, 
                (int)this.Status, 
                this.Status.ToString(), 
                Environment.NewLine);

            foreach (var header in this.Headers)
            {
                s.AppendFormat("{0}: {1}{2}", header.Key.ToString(), header.Value.ToString(), Environment.NewLine);
            }

            if (!this.Headers.ContainsKey("Content-Length") && this.Body != null)
            {
                s.AppendFormat("Content-Length: {0}{1}", this.Body.Length, Environment.NewLine);
            }

            s.AppendLine();

            var headerBytes = System.Text.Encoding.UTF8.GetBytes(s.ToString());
            if (this.Body == null)
            {
                return headerBytes;
            }

            return this.Combine(headerBytes, this.Body);
        }

        private byte[] Combine(byte[] a, byte[] b)
        {
            byte[] c = new byte[a.Length + b.Length];
            System.Buffer.BlockCopy(a, 0, c, 0, a.Length);
            System.Buffer.BlockCopy(b, 0, c, a.Length, b.Length);
            return c;
        }

        public void Send(NetworkStream stream)
        {
            var output = this.ToResponseOutput();

            BinaryWriter writer = new BinaryWriter(stream);
            writer.Write(output);
            writer.Flush();
        }
    }
}
